package com.miplus.ccrm.core.service.aiqm;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.miplus.ccrm.common.*;
import com.miplus.ccrm.core.controller.vo.aicall.BatchRepReqVo;
import com.miplus.ccrm.core.controller.vo.aicall.BatchRepResVo;
import com.miplus.ccrm.core.controller.vo.aicall.ImpObCaseResVo;
import com.miplus.ccrm.core.controller.vo.aicall.ObCallListResVo;
import com.miplus.ccrm.core.controller.vo.aiqm.*;
import com.miplus.ccrm.core.controller.vo.ficase.ImpResultVo;
import com.miplus.ccrm.core.controller.vo.file.UploadResVo;
import com.miplus.ccrm.core.controller.vo.strategy.PreViewTrigReqVo;
import com.miplus.ccrm.core.mapper.*;
import com.miplus.ccrm.core.pojo.*;
import com.miplus.ccrm.core.service.ExportService;
import com.miplus.ccrm.core.service.collect.FiCreditcasesService;
import com.miplus.ccrm.core.service.collect.FiImportHistService;
import com.miplus.ccrm.core.service.strategy.CpCalllistService;
import com.miplus.ccrm.core.service.strategy.CpCalllistTriggerQuerylinkService;
import com.miplus.ccrm.core.service.strategy.CpCalllistTriggerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author pc
 * @description 针对表【QM_DATA(质检数据表)】的数据库操作Service实现
 * @createDate 2024-11-04 12:03:46
 */
@Service
@Slf4j
public class QmDataServiceImpl extends MPJBaseServiceImpl<QmDataMapper, QmData>
        implements QmDataService {
    @Resource
    private CpCalllistTriggerMapper triggerMapper;
    @Resource
    private FiCreditcasesService caseService;
    @Resource
    private FiImportHistService fiImportHistService;
    @Resource
    private CpCalllistMapper cpCalllistMapper;
    @Resource
    private ExportService exportService;
    @Resource
    private TRecorderService recorderService;
    @Resource
    private QmRulesMapper qmRulesMapper;
    @Resource
    private AsrCallhistMapper asrCallhistMapper;
    @Resource
    private QmGradeMapper qmGradeMapper;
    @Resource
    private QmTemplateMapper qmTemplateMapper;
    @Value("${ccrm.qm.maxcnt:}")
    private Integer qmOneMaxCnt;
    @Resource
    private CpCalllistTriggerQuerylinkService triggerQuerylinkService;

    private MPJLambdaWrapper<TRecorder> getImpQueryWrapper(Integer triggerid) {
        String noinctags = "";
        CpCalllistTrigger trigger = triggerMapper.selectById(triggerid);
        String tags = JPubUtils.getInString(trigger.getCusttags());
        if (JPubUtils.IsNotEmpty(tags)) {
            noinctags = JPubUtils.BoolToString(trigger.getNoinctag());
        }

        //MPJLambdaWrapper quyWrapper = new MPJLambdaWrapper<TRecorder>()
        MPJLambdaWrapper<TRecorder> quyWrapper = new MPJLambdaWrapper<>();
//        MPJLambdaWrapper quyWrapper=new MPJLambdaWrapper<FiCreditcases>()
//                .innerJoin(ConCustomer.class, "cu", ConCustomer::getCustomernumber, FiCreditcases::getCustomernumber)
//                .innerJoin(FiTask.class,"tk",FiTask::getOriginnumber,FiCreditcases::getCreditcaseid)
//                .innerJoin(TRecorder.class,"tr",TRecorder::getCallid,FiTask::getCticallid)
//                .ge(JPubUtils.IsNotEmpty(trigger.getMthsodue()), FiCreditcases::getMthsOdue, trigger.getMthsodue())
//                .le(JPubUtils.IsNotEmpty(trigger.getMthsodue2()), FiCreditcases::getMthsOdue, trigger.getMthsodue2())
//                .ge(JPubUtils.IsNotEmpty(trigger.getOverday1()), FiCreditcases::getMthsDay, trigger.getOverday1())
//                .le(JPubUtils.IsNotEmpty(trigger.getOverday2()), FiCreditcases::getMthsDay, trigger.getOverday2())
//                .isNotNull(FiTask::getCticallid)
        //.apply(JPubUtils.IsEqual(noinctags, 0),String.format("cu.customernumber in (select tag.custid from con_customertag tag where tag.custid=t.customernumber and tag.id in ('%s'))", tags))
        //.apply(JPubUtils.IsEqual(noinctags, 1), String.format("cu.customernumber not in (select tag.custid from con_customertag tag where tag.custid=t.customernumber and tag.id in ('%s'))", tags))
        //.notIn(FiTask::getCticallid,"select d.dataid from qm_data d");
        //.in(TRecorder::getAgentid,ids)
        quyWrapper.notIn(TRecorder::getCallid, "select d.dataid from qm_data d");

        if (JPubUtils.IsNotEmpty(trigger.getUsrid())) {
            String[] usrId = trigger.getUsrid().split(",");
            quyWrapper.in(TRecorder::getAgentid, Arrays.asList(usrId));
        }
        quyWrapper = triggerQuerylinkService.buildQueryByQmWrapper(quyWrapper, triggerid);

        return quyWrapper;
    }

    @Override
    public IPage<QmViewResVo> preViewQmData(String triggerid, Integer pagenum, Integer pagesize) {
        Integer trint = Integer.parseInt(triggerid);
        MPJLambdaWrapper<TRecorder> quyWrapper = getImpQueryWrapper(trint);
        //return caseService.selectJoinListPage(new Page<>(pagenum, pagesize),
        return recorderService.selectJoinListPage(new Page<>(pagenum, pagesize),
                QmViewResVo.class,
                //quyWrapper.selectAs(FiCreditcases::getCreditcaseid, QmViewResVo::getFicaseid)
                //.selectAs(FiTask::getTasknumber,QmViewResVo::getTaskid)
                quyWrapper.selectAs(TRecorder::getStarttime, QmViewResVo::getCrdt)
                        .selectAs(TRecorder::getCallid, QmViewResVo::getCallcaseid)
                        .selectAs(TRecorder::getTelno, QmViewResVo::getAni)
                        .selectAs(TRecorder::getTeldnis, QmViewResVo::getDnis)
                        .selectAs(TRecorder::getSpendtime, QmViewResVo::getConnectspan)
                        .selectAs(TRecorder::getCalltype, QmViewResVo::getCalltype)
                        .selectAs(TRecorder::getAgentid, QmViewResVo::getUsrid)
                        .selectAs(TRecorder::getTaskflag, QmViewResVo::getTaskflag)
                        .selectAs("(select u.name from sys_user u where u.usrid=t.agentid)", QmViewResVo::getUsrname)
                        .selectAs("(select g.grpname from sys_user u join sys_grp g on g.grpid=u.groups where u.usrid=t.agentid)", QmViewResVo::getGrpname)
        );
    }

    @Override
    public IPage<QmViewResVo> preViewQmData(PreViewTrigReqVo paras) {
        CpCalllist calllist = cpCalllistMapper.selectById(paras.getClid());
        String triggerid = calllist.getTriggerid();
        if (JPubUtils.IsEmpty(triggerid)) {
            throw new ServiceException(EnumRCode.NoFindConfig.value, EnumRCode.NoFindConfig.name);
        }
        return preViewQmData(triggerid, 1, JPubUtils.exportMaxCount);
    }

    private List<QmViewResVo> buildImpData(String triggerid) {
        IPage<QmViewResVo> pages = preViewQmData(triggerid, 1, JPubUtils.exportMaxCount);
        return pages.getRecords();
    }

    private List<QmViewResVo> buildImpData(List<UploadResVo> list) {
        List<QmViewResVo> pagelist = new ArrayList<>();
        for (UploadResVo resVo : list) {
            QmViewResVo p = new QmViewResVo();
            p.setCallcaseid(resVo.getFilekey());
            pagelist.add(p);
        }

        return pagelist;
    }

    @Override
    public ImpResultVo importQmData(String usrid, ImpQmDataReqVo paras) {
        ImpResultVo resultVo = null;
        String triggerid = "";
        String imptype = paras.getImptype();
        CpCalllist calllist = cpCalllistMapper.selectById(paras.getClid());
        String tempid = calllist.getSendmodel();
        if (JPubUtils.IsEqual(imptype, "file")) {
            List<QmViewResVo> list = buildImpData(paras.getDatalist());
            resultVo = importQmData(usrid, paras.getClid(), "", paras.getBatchdsc(), imptype, tempid, list);
        } else {
            triggerid = calllist.getTriggerid();
            if (JPubUtils.IsEmpty(triggerid)) {
                throw new ServiceException(EnumRCode.NoFindConfig.value, EnumRCode.NoFindConfig.name);
            }
            resultVo = importQmData(usrid, calllist.getClid(), triggerid, paras.getBatchdsc(), imptype, tempid);
        }

        return resultVo;
    }

    @Override
    public ImpResultVo importQmData(String usrid, String clid, String triggerid, String batchdsc, String imptype, String tempid) {
        List<QmViewResVo> list = buildImpData(triggerid);
        return importQmData(usrid, clid, triggerid, batchdsc, imptype, tempid, list);
    }

    public ImpResultVo importQmData(String usrid, String clid, String triggerid, String batchdsc,
                                    String imptype, String tempid, List<QmViewResVo> list) {
        int okcnt = 0;
        SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmmssSSS");
        String batchid = 'T' + df.format(new Date());
        //先写一个后面在update，目的是为了写入数据异常，可以delete掉
        fiImportHistService.AddImportHist(batchid,
                batchdsc,
                usrid,
                0,
                "qmtemplate",
                triggerid,
                list.size(),
                okcnt,
                clid,
                imptype
        );

        log.info("importQmData:Records={}", list.size());
        List<QmData> dataList = new ArrayList<>();
        for (QmViewResVo p : list) {
            QmData qmData = new QmData();
            qmData.setDataid(p.getCallcaseid());
            if (JPubUtils.IsEqual(p.getTaskflag(), "2")) {
                //质检状态：0:未就绪，1：待质检；2：已质检；3：已复检
                qmData.setQmstatus("1");
            } else {
                qmData.setQmstatus("0");
            }
            qmData.setQmtype("record");
            qmData.setTemplateid(tempid);
            qmData.setClid(clid);
            qmData.setAgainusr(usrid);
//            if(JPubUtils.IsNotEmpty(p.getFicaseid())) {
//                qmData.setFicaseid(p.getFicaseid());
//            }
//            if(JPubUtils.IsNotEmpty(p.getTaskid())) {
//                qmData.setTaskid(p.getTaskid());
//            }
            qmData.setBatchid(batchid);
            qmData.setCrusr(usrid);
            qmData.setCrdt(new Date());
            qmData.setMdusr(usrid);
            qmData.setMddt(new Date());

            dataList.add(qmData);
            okcnt++;
        }
        saveBatch(dataList);
        fiImportHistService.UpImportHist(batchid, okcnt);

        list.clear();
        dataList.clear();

        ImpResultVo resultVo = new ImpResultVo();
        resultVo.setBatchid(batchid);
        resultVo.setOkcnt(okcnt);
        resultVo.setFailcnt(0);

        return resultVo;
    }

    private MPJLambdaWrapper getQueryWrapper(QmCaseReqVo paras) {
        return new MPJLambdaWrapper<QmData>()
                .leftJoin(TRecorder.class, "tr", TRecorder::getCallid, QmData::getDataid)
                .leftJoin(CpCalllist.class, "cp", CpCalllist::getClid, QmData::getClid)
                .between(JPubUtils.IsNotEmpty(paras.getStartdt()), QmData::getCrdt, JPubUtils.StringToDate(paras.getStartdt()), JPubUtils.StringToDate(paras.getEnddt()))
                .between(JPubUtils.IsNotEmpty(paras.getQmstartdt()), QmData::getQmdt, JPubUtils.StringToDate(paras.getQmstartdt()), JPubUtils.StringToDate(paras.getQmenddt()))
                .eq(JPubUtils.IsNotEmpty(paras.getQmstatus()), QmData::getQmstatus, paras.getQmstatus())
                .eq(JPubUtils.IsNotEmpty(paras.getClid()), QmData::getClid, paras.getClid())
                .eq(JPubUtils.IsNotEmpty(paras.getBatchid()), QmData::getBatchid, paras.getBatchid())
                .ge(JPubUtils.IsNotEmpty(paras.getQmpoint1()), QmData::getTotalpoint, paras.getQmpoint1())
                .le(JPubUtils.IsNotEmpty(paras.getQmpoint2()), QmData::getTotalpoint, paras.getQmpoint2())
                .eq(JPubUtils.IsNotEmpty(paras.getUsrid()), TRecorder::getAgentid, paras.getUsrid())
                .eq(JPubUtils.IsNotEmpty(paras.getFicaseid()), QmData::getFicaseid, paras.getFicaseid())
                .eq(JPubUtils.IsNotEmpty(paras.getIsok()), QmData::getIsok, paras.getIsok())
                .exists(JPubUtils.IsNotEmpty(paras.getGrpid()), String.format("select 1 from sys_user u where u.groups='%s' and u.usrid=tr.agentid", paras.getGrpid())
                );
    }

    @Override
    public IPage<QmCaseResVo> qmDataList(QmCaseReqVo paras) {//ani，dnis，calltype 不再显示，没有意义
        MPJLambdaWrapper<QmData> quyWrapper = getQueryWrapper(paras);
        return selectJoinListPage(new Page<>(paras.getPageNum(), paras.getPageSize()),
                QmCaseResVo.class,
                quyWrapper.selectAs(TRecorder::getAgentid, QmCaseResVo::getUsrid)
                        .selectAs(CpCalllist::getName, QmCaseResVo::getClidname)
                        .selectAs("fun_getnames('QM.STATUS',t.qmstatus)", QmCaseResVo::getQmstatusdsc)
                        .selectAs("fun_getnames('QM.RESULT',t.isok)", QmCaseResVo::getIsokdsc)
                        .selectAs("(select u.name from sys_user u where u.usrid=tr.agentid)", QmCaseResVo::getUsrname)
                        .selectAs("(select g.grpname from sys_user u join sys_grp g on g.grpid=u.groups where u.usrid=tr.agentid)", QmCaseResVo::getGrpname)
                        .selectAs(TRecorder::getSpendtime, QmCaseResVo::getConnectspan)
                        .selectAll(QmData.class)
                        .orderByAsc(QmData::getCrdt)
        );
    }

    @Override
    public CmdResVo expQmData(JSysUser user, QmCaseReqVo paras, HttpServletResponse response) {
        String $usrid = user.getUsrid();
        int pagesize = paras.getPageSize();
        if (pagesize > JPubUtils.exportMaxCount) {
            paras.setPageSize(JPubUtils.exportMaxCount);
        }
        log.info("expQmData:pagesize={}", pagesize);

        IPage<QmCaseResVo> pages = qmDataList(paras);
        ArrayList arr = new ArrayList();

        String exptempid = JPubUtils.getExpTempID(paras.getExpfilename(), "质检数据表");
        String filename = JPubUtils.getExpFileName(
                paras.getExpfilename(), exptempid
        );
        pages.convert(u -> {
            HashMap map = JPubUtils.toExportMap(u);
            if (map != null) arr.add(map);
            return u;
        });
        CmdResVo resVo = exportService.ToExcel(
                response,
                arr,
                paras.getExpidlist(),
                paras.getExpnamelist(),
                filename,
                $usrid
        );

        int okcount = resVo.getCount();
        if (okcount > 0) {
            fiImportHistService.AddExportHist(
                    resVo.getKeyId(),
                    $usrid,
                    exptempid,
                    filename,
                    okcount
            );
        }
        arr.clear();

        return resVo;
    }

    @Override
    public CmdResVo checkResult(String $usrid, QmCheckVo paras) {
        int ret = baseMapper.update(null, new UpdateWrapper<QmData>()
                .lambda()
                .set(JPubUtils.IsNotEmpty(paras.getScore()), QmData::getTotalpoint1, paras.getScore())
                .set(JPubUtils.IsNotEmpty(paras.getIsok()), QmData::getIsok, paras.getIsok())
                .set(QmData::getCheckqmdsc, paras.getRemark())
                .set(QmData::getMddt, new Date())
                .set(QmData::getCheckqmer, $usrid)
                .set(QmData::getQmstatus, "3")
                .eq(QmData::getDataid, paras.getDataid())
        );

        return new CmdResVo(ret, paras.getDataid());
    }

    @Override
    public ImpResultVo uploadResult(JSysUser user, ImpQmDataReqVo paras) {
        if (JPubUtils.IsEmpty(paras.getDatalist())) {
            log.warn("uploadResult.nofind data");
            return null;
        }
        List<TRecorder> recorderList = new ArrayList<>();
        for (UploadResVo p : paras.getDatalist()) {
            TRecorder recorder = new TRecorder();
            recorder.setRecorderid(p.getFilekey());
            recorder.setFilename(p.getFilename());
            recorder.setRecorderip(p.getIpaddr());
            recorder.setChannelno(-1);
            recorder.setStarttime(new Date());
            recorder.setStartdate(new Date());
            if (JPubUtils.IsEmpty(p.getRecspan())) {
                recorder.setSpendtime(BigDecimal.ZERO);
            } else {
                recorder.setSpendtime(new BigDecimal(p.getRecspan()));
            }
            recorder.setAvailable("1");
            recorder.setFilepath(p.getFiledir());
            recorder.setCallid(p.getFilekey());
            recorder.setAgentid("qm");
            recorderList.add(recorder);
        }
        Boolean bret = recorderService.saveBatch(recorderList);

        ImpResultVo resultVo = null;
        log.info("uploadResult.saveBatch={}", bret);
        if (bret) {
            resultVo = importQmData(user.getUsrid(), paras);
        }
        recorderList.clear();
        return resultVo;
    }

    @Override
    public CmdResVo doAiQm(String usrid, QmCaseReqVo paras) {
        MPJLambdaWrapper<QmData> quyWrapper = getQueryWrapper(paras);
        List<QmCaseResVo> qmCaseResVoList = selectJoinList(QmCaseResVo.class,
                quyWrapper.select(QmData::getDataid)
                        .select(QmData::getTemplateid)
                        .eq(QmData::getQmstatus, "1")
                        .le("rownum", qmOneMaxCnt)
        );
        int qmcnt = 0;
        if (JPubUtils.IsEmpty(qmCaseResVoList)) {
            log.info("doAiQm.Count=0");
            return new CmdResVo(qmcnt);
        }
        log.info("doAiQm.Count={}", qmCaseResVoList.size());
        for (QmCaseResVo resVo : qmCaseResVoList) {
            if (JPubUtils.IsEmpty(resVo.getTemplateid())) {
                log.warn("dataQuality({}) Template is Null", resVo.getDataid());
                continue;
            }
            qmcnt += dataQuality(usrid, resVo.getDataid(), resVo.getTemplateid());
        }

        return new CmdResVo(qmcnt);
    }

    private int dataQuality(String usrid, String dataid, String templateid) {
        Integer tempid = JPubUtils.StringToInt(templateid);
        QmTemplate qmTemplate = qmTemplateMapper.selectById(tempid);
        if (qmTemplate == null) {
            log.warn("dataQuality({}) Template={} NoFind", dataid, tempid);
            throw new ServiceException(EnumRCode.NoFindConfig.value, dataid + " NoFindTemp:" + templateid);
        }

        List<QmRules> rulesList = qmRulesMapper.selectList(new MPJLambdaWrapper<QmRules>()
                .innerJoin(QmTemprulesLink.class, "tl", QmTemprulesLink::getRulesid, QmRules::getRulesid)
                .selectAll(QmRules.class)
                .eq(QmTemprulesLink::getTemplateid, tempid)
        );
        if (JPubUtils.IsEmpty(rulesList)) {
            log.warn("dataQuality({}) Template={} NoFind Rules", dataid, tempid);
            throw new ServiceException(EnumRCode.NoFindConfig.value, dataid + " NoFindRule:" + templateid);
        }
        List<AsrCallhist> callhistList = asrCallhistMapper.selectList(
                new MPJLambdaWrapper<AsrCallhist>()
                        .eq(AsrCallhist::getCallid, dataid)
                        .selectAll(AsrCallhist.class)
                        .orderByAsc(AsrCallhist::getAsrid)
        );
        if (JPubUtils.IsEmpty(callhistList)) {//这种情况应该不存在
            log.warn("dataQuality({}) NoFind Asrlist", dataid);
            return 0;
        }
        log.info("dataQuality({}) Template={}..", dataid, tempid);
        Integer total = 100;
        DlgContent dlgContent = buildContent(callhistList);
        for (QmRules rule : rulesList) {
            String keyval = rule.getKeyval();
            if (JPubUtils.IsEmpty(keyval) || keyval.length() < 2)
                continue;
            String qmcontent = dlgContent.getContent(rule.getQmrole(), rule.getQmrange());
            if (JPubUtils.IsEmpty(qmcontent))
                continue;
            Pattern pattern = Pattern.compile(keyval);
            Matcher matcher = pattern.matcher(qmcontent);
            int point = rule.getPoint();
            String ismatch = "0";
            if (matcher.matches()) {
                ismatch = "1";
                if (JPubUtils.IsEqual(rule.getPmopt(), "-")) {
                    total -= rule.getPoint();
                    point = 0 - point;
                } else {
                    total += rule.getPoint();
                }
            }
            writeGrade(dataid, rule.getRulesid(), point, ismatch);
        }
        if (total > 100) total = 100;
        else if (total < 0) total = 0;

        BigDecimal adoptscore = qmTemplate.getAdoptscore();
        BigDecimal pointsc = new BigDecimal(total);
        log.info("dataQuality({}) point={},adoptscore={}..", dataid, total, adoptscore);
        QmData updata = new QmData();
        updata.setDataid(dataid);
        updata.setQmstatus("2");
        updata.setTotalpoint(pointsc);
        updata.setQmer("ai");
        updata.setMddt(new Date());
        updata.setMdusr(usrid);
        updata.setQmdt(new Date());//2025-01-06
        if (pointsc.compareTo(adoptscore) >= 0) {
            updata.setIsok("1");
        } else {
            updata.setIsok("0");
        }
        return baseMapper.updateById(updata);
    }

    private DlgContent buildContent(List<AsrCallhist> callhistList) {
        DlgContent dlgContent = new DlgContent();
        for (AsrCallhist h : callhistList) {
            dlgContent.addStr(h.getAsrcontent(), h.getAsrstatus());
        }
        for (int i = callhistList.size() - 1; i > 0; i--) {
            AsrCallhist h = callhistList.get(i);
            dlgContent.addEnd(h.getAsrcontent(), h.getAsrstatus());
        }
        dlgContent.buildAll();
        return dlgContent;
    }

    private void writeGrade(String dataid, Integer ruleid, Integer point, String ismatch) {
        QmGrade grade = new QmGrade();
        grade.setDataid(dataid);
        grade.setOptionid(ruleid);
        grade.setPoint(new BigDecimal(point));
        grade.setIsmatch(ismatch);
        if (JPubUtils.IsEqual(ismatch, "1")) {
            grade.setScore(new BigDecimal(point));
        } else {
            grade.setScore(BigDecimal.ZERO);
        }
        grade.setCrdt(new Date());
        grade.setCrusr("ai");
        grade.setMddt(new Date());
        grade.setMdusr("ai");
        qmGradeMapper.insert(grade);
    }
}




